package ontocompo.fractalcomponentmanager.lib;

import java.rmi.RMISecurityManager;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;
import java.util.HashMap;

import ontocompo.fractalcomponentmanager.api.ManagerItf;
import ontocompo.fractalcomponentmanager.api.WebApplicationItf;
import ontocompo.fractalcomponentmanager.enums.UpdateComponentType;
import ontocompo.fractalcomponentmanager.serializable.WebApplicationSerializable;

public class Manager implements ManagerItf {
	private CompoApplication ca;
	
	public Manager() {
		this.ca = new CompoApplication();
	}
	
	@Override
	public boolean loadAndInitApp(String appComponentUid) throws RemoteException {
		if(! Resources.LOADED_APPS.containsKey(appComponentUid)) {
			if(Resources.AVAILABLE_APPS.containsKey(appComponentUid)) {
				WebApplication webApp = Resources.AVAILABLE_APPS.remove(appComponentUid);
				if(webApp.loadAndInit()) {
					Resources.LOADED_APPS.put(appComponentUid, webApp);
				} else {
					return false;
				}
			} else {
				return false;
			}
		}
		return false;
	}

	@Override
	public String getHTMLInterface(String appComponentUid) throws RemoteException {
		if(Resources.LOADED_APPS.containsKey(appComponentUid)) {
			return Resources.LOADED_APPS.get(appComponentUid).getHTMLInterface();
		} else {
			return "Une erreur s'est produite.";
		}
	}

	@Override
	public void updateUIElement(UpdateComponentType type, String appComponentUid, String uiElementId, String newValue) throws RemoteException {
		if(Resources.LOADED_APPS.containsKey(appComponentUid)) {
			Resources.LOADED_APPS.get(appComponentUid).updateUIElement(type, uiElementId, newValue);
		}
	}

	@Override
	public void triggerAction(String appComponentUid, String uiElementId) throws RemoteException {
		if(Resources.LOADED_APPS.containsKey(appComponentUid)) {
			Resources.LOADED_APPS.get(appComponentUid).triggerAction(uiElementId);
		}
	}

	public static void main(String[] args) {
		if (System.getSecurityManager() == null) {
            System.setSecurityManager(new RMISecurityManager());
        }
		
		System.getSecurityManager().checkAccept("localhost",1099);
		
        try {
            String name = "Manager";
            ManagerItf ac = new Manager();
            ManagerItf stub = (ManagerItf) UnicastRemoteObject.exportObject(ac, 0);
            Registry registry = LocateRegistry.getRegistry();
            registry.rebind(name, stub);
            System.out.println("Manager bound");
            Resources.buildAvailableApplications();
            System.out.println("Available Applications List built.");
            
 //           ac.test();
        } catch (Exception e) {
            System.err.println("Manager exception:");
            e.printStackTrace();
        }
	}

	@Override
	public HashMap<String, String> getAvailableApps() throws RemoteException {
		HashMap<String, String> appList = new HashMap<String, String>();
		for(String appId: Resources.AVAILABLE_APPS.keySet()) {
			appList.put(appId, Resources.AVAILABLE_APPS.get(appId).getName());
		}
		return appList;
	}

	@Override
	public ArrayList<String> getLoadedAppStringList() throws RemoteException {
		ArrayList<String> loadedAppList = new ArrayList<String>();
		for(String appId: Resources.LOADED_APPS.keySet()) {
			loadedAppList.add(Resources.LOADED_APPS.get(appId).getName());
		}
		return loadedAppList;
	}
	
	@Override
	public ArrayList<WebApplicationItf> getLoadedApp() {
		ArrayList<WebApplicationItf> result = new ArrayList<WebApplicationItf>();
		for(WebApplication wa : Resources.LOADED_APPS.values()) {
			WebApplicationSerializable waz = new WebApplicationSerializable(wa.getAppId(), wa.getName(), wa.getHTMLInterface(), wa.getSelectableUIElementsIds(), wa.getSelectedUIElementsIds(), wa.getSelectedUIElementsIdsAndHtml(), wa.getSelectedUIElementsForSubstitutionsHtmlIds());
			result.add(waz);
		}
		return result;
	}

	@Override
	public void selectAllUIElements(String appComponentUid) {
		WebApplication wa = Resources.LOADED_APPS.get(appComponentUid);
		wa.selectAllUIElements();
		
		this.ca.addToBaseWebApp(wa);
	}
	
	@Override
	public void selectForSubstitution(String elementId) {
		for(WebApplication wa : Resources.LOADED_APPS.values()) {
			if(wa.containsElement(elementId)) {
				wa.selectElementForSubstitution(elementId);
			}
		}
	}
	
	@Override
	public void performSubstitution(String elementId) {
		this.ca.performSubstitution(elementId);
	}
	
	@Override
	public void saveCompo(String appName) {
		this.ca.setAppName(appName);
		this.ca.generateComposedApplication();
	}
	
	@Override
	public void test() {
		System.out.println("Begin Test!");
		try {
			this.loadAndInitApp("ontowebapp.reversestring.ReverseStringApp");
			this.loadAndInitApp("ontowebapp.trimstring.TrimStringApp");
			ArrayList<WebApplicationItf> lApp = this.getLoadedApp();
			
			for(WebApplicationItf wai : lApp) {
				this.selectAllUIElements(wai.getAppId());
			}
			
			/* Substitutions d'1 outputs et d'1 input (on garde le output) */
			this.selectForSubstitution("ontowebapp.trimstring.ui.lib.TrimStringResult");
			this.selectForSubstitution("ontowebapp.reversestring.ui.lib.TextToReverseInput");
			this.performSubstitution("ontowebapp.trimstring.ui.lib.TrimStringResult");
			
			/* Substitutions de 2 boutons */
			this.selectForSubstitution("ontowebapp.reversestring.ui.lib.ReverseButton");
			this.selectForSubstitution("ontowebapp.trimstring.ui.lib.TrimButton");
			this.performSubstitution("ontowebapp.trimstring.ui.lib.TrimButton");
			
			/* Substitutions de 2 inputs */
			//this.selectForSubstitution("ontowebapp.trimstring.ui.lib.TextToTrimInput");
			//this.selectForSubstitution("ontowebapp.reversestring.ui.lib.TextToReverseInput");
			//this.performSubstitution("ontowebapp.trimstring.ui.lib.TextToTrimInput");
			
			/* Substitutions de 2 outputs */
			this.selectForSubstitution("ontowebapp.trimstring.ui.lib.TrimStringResult");
			this.selectForSubstitution("ontowebapp.reversestring.ui.lib.ReverseStringResult");
			this.performSubstitution("ontowebapp.reversestring.ui.lib.ReverseStringResult");		
			
			this.saveCompo("ReverseTrim");
			
		} catch (RemoteException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("End Test!");
	}
}
